﻿using System;
using System.Collections.Generic;
using System.Linq;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.EventSystems;
using Random = UnityEngine.Random;

public static class CommonTools
{
    static Unity.Mathematics.Random m_Random = new Unity.Mathematics.Random();
    static bool RandomInited = false;
    public static Unity.Mathematics.Random GetRandom()
    {
        if (!RandomInited)
        {
            m_Random = new Unity.Mathematics.Random();
            m_Random.InitState((uint)DateTime.Now.Ticks);
            RandomInited = true;
        }
        return m_Random;
    }
    // Unity获取随机整型值

    public static int RandomInt(int min, int max)
    {
        return Random.Range(min, max);
    }

    public static float RandomFloat(float min, float max)
    {

        return Random.Range(min, max);
    }
    public static Vector3 RandomVector3(Vector3 min, Vector3 max)
    {
        return new Vector3(RandomFloat(min.x, max.x), RandomFloat(min.y, max.y), RandomFloat(min.z, max.z));
    }

    public static bool IsFloatValid(float value)
    {
        if (float.IsInfinity(value))
            return false;
        if (float.IsNaN(value))
            return false;

        return true;
    }
    public static bool CheckVectorData(Vector3 vec)
    {
        if (!IsFloatValid(vec.x))
            return false;
        if (!IsFloatValid(vec.y))
            return false;
        if (!IsFloatValid(vec.z))
            return false;
        return true;
    }

    public static float GetAnglePlane(Vector3 start, Vector3 end)
    {
        start = start - Vector3.Project(start, Vector3.up);
        end = end - Vector3.Project(end, Vector3.up);
        return Vector3.Angle(start, end);
    }
    public static Vector3 GetDirection(Vector3 start, Vector3 end)
    {
        return (end - start).normalized;
    }
    // 获取水平距离
    public static float GetDistance(Vector3 start, Vector3 end)
    {
        start.y = 0;
        end.y = 0;
        return Vector3.Distance(start, end);
    }
    public static float GetPathLenght(Vector3[] pathPoint)
    {
        float fDis = 0;
        for (int i = 0; i < pathPoint.Length - 1; ++i)
        {
            fDis += Vector3.Distance(pathPoint[i], pathPoint[i + 1]);
        }
        return fDis;
    }
    public static float GetCurrentTime(bool isIgnoreTimeScale)
    {
        return isIgnoreTimeScale ? Time.realtimeSinceStartup : Time.time;
    }
    //获取当前时间
    public static float GetDeltaTime(bool isIgnoreTimeScale)
    {
        return (isIgnoreTimeScale && Time.timeScale == 0f) ? Time.unscaledDeltaTime : Time.deltaTime;
    }

    // 获取当前时间戳
    public static long GetNowDateTime()
    {
        return SG.Utils.ConvertDateTimeToLong(System.DateTime.Now);
    }

    public static bool IsTimeStoped(bool isIgnoreTimeScale)
    {
        if (isIgnoreTimeScale == true && Time.timeScale == 0f)
        {
            return false;
        }
        else if (isIgnoreTimeScale == false && Time.timeScale == 0f)
        {
            return true;
        }

        return false;
    }
    public static int GetListIndex(string strKey)
    {
        int index = strKey.IndexOf("_");
        strKey = strKey.Substring(index + 1);
        if (int.TryParse(strKey, out index))
            return index;
        return -1;
    }
    public static string GetKeyValue(string strKey)
    {
        int index = strKey.IndexOf("_");
        strKey = strKey.Substring(index + 1);
        return strKey;
    }

    public static Vector3 RandomDirection()
    {
        Vector3 dir = RotateVector(Vector3.forward, Vector3.up, RandomFloat(0, 360));
        return dir;
    }

    public static Vector3 RandomCircle(Vector3 center, float min, float max)
    {
        Vector3 dir = RandomDirection();
        return center + RandomFloat(min, max) * dir;
    }
    public static Vector2 RandomCircle(Vector2 center, float min, float max)
    {
        Vector2 dir = RandomDirection();
        return center + RandomFloat(min, max) * dir;
    }

    /// <summary>
    /// 获得随机列表里的随机一项
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="itemList"></param>
    /// <returns></returns>
    public static T GetRandList<T>(List<T> itemList) where T : class
    {
        int nCount = itemList.Count;
        if (nCount < 1)
            return null;
        if (nCount == 1)
            return itemList[0];
        return itemList[CommonTools.RandomInt(0, nCount - 1)];
    }
    /// <summary>
    /// 清理列表里的空项
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="itemList"></param>
    public static void ClearListNullItem<T>(List<T> itemList)
    {
        for (int i = 0; i < itemList.Count;)
        {
            if (itemList[i] == null)
            {
                itemList.RemoveAt(i);
                continue;
            }
            ++i;
        }

    }

    public static int GetItemFromRateList(List<int> items)
    {
        if (!items.Any())
        {
            throw new InvalidOperationException("列表不能为空");
        }

        // 计算权重总和  
        int totalWeight = items.Sum(i => i);

        // 如果权重总和为0，则随机选择一项  
        if (totalWeight == 0)
        {
            return RandomInt(0, items.Count());
        }

        // 生成随机数  
        System.Random random = new System.Random();
        int randomNumber = random.Next(totalWeight);

        // 计算权重累积和，并找到随机数落入的区间  
        int currentSum = 0;
        for (int i = 0; i < items.Count; ++i)
        {
            currentSum += items[i];
            if (randomNumber < currentSum)
            {
                return i;
            }
        }

        // 如果执行到这里，说明有问题（理论上不会到达这里）  
        throw new InvalidOperationException("未能按照权重选中项");
    }
    //一个向量向另一个向量旋转指定角度
    public static Vector3 RotateTowards(Vector3 from, Vector3 to, float degrees)
    {

        return Quaternion.Euler(0, 0, degrees) * from;
    }

    public static float GetAngle(Vector3 vector1, Vector3 vector2)
    {
        double sin = vector1.x * vector2.z - vector2.x * vector1.z;
        double cos = vector1.x * vector2.x + vector1.z * vector2.z;

        return (float)(Math.Atan2(sin, cos) * (180 / Math.PI));
    }
    public static float GetAngle(Vector2 vector1, Vector2 vector2)
    {
        double sin = vector1.x * vector2.y - vector2.x * vector1.y;
        double cos = vector1.x * vector2.x + vector1.y * vector2.y;

        return (float)(Math.Atan2(sin, cos) * (180 / Math.PI));
    }
    public static float GetAngle(Vector3 dir)
    {
        dir.y = 0;
        return Mathf.Atan2(
            Vector3.Dot(Vector3.up, Vector3.Cross(dir, Vector3.forward)),
            Vector3.Dot(dir, Vector3.forward)) * Mathf.Rad2Deg;
    }

    // 指定的点是不是在某个tag叫做 strLayerName的界面上
    public static bool IsPositionOverLayer(Vector2 pos, string strLayerName)
    {
        List<RaycastResult> results = new List<RaycastResult>();
        PointerEventData eventData = new PointerEventData(EventSystem.current);
        eventData.position = new Vector2(pos.x, pos.y);
        EventSystem.current.RaycastAll(eventData, results);
        for (int i = 0; i < results.Count; i++)
        {
            if (results[i].gameObject.layer == LayerMask.NameToLayer( strLayerName ) )
            {
                return true;
            }
        }

        return false;
    }


    public static float SignedAngleBetween(Vector3 from, Vector3 to, Vector3 dir)
    {
        float angle = Vector3.Angle(from, to);
        float sign = Mathf.Sign(Vector3.Dot(dir, Vector3.Cross(from, to)));
        float signed_angle = angle * sign;
        return (signed_angle <= 0) ? 360 + signed_angle : signed_angle;
    }

    public static float AngleGet(Vector3 from, Vector3 to)
    {
        Vector3 v3 = Vector3.Cross(from, to);
        if (v3.z > 0)
            return Vector3.Angle(from, to);
        else
            return 360 - Vector3.Angle(from, to);
    }
    // 旋转一个矢量
    public static Vector3 RotateVector(Vector3 dir, Vector3 axis, float angel)
    {
        return Quaternion.AngleAxis(angel, axis) * dir;
    }
    public static Vector3 RotateRound(Vector3 position, Vector3 center, Vector3 axis, float angle)
    {
        var dir = position - center;
        dir = RotateVector(dir, Vector3.up, angle);
        return center + dir;

    }
    // 得到一个向量的法线，相对于up或者forward的法线
    public static Vector3 GetNormalLine(Vector3 dir, Vector3 dir2)
    {
        // 如果和正上方重合了，
        if (dir.Equals(Vector3.up))
        {
            return Vector3.Cross(dir, dir2);
        }
        return -Vector3.Cross(dir, Vector3.up);
    }
    public static Vector3 MoveVector(Vector3 start, Vector3 dir, Vector3 offset)
    {
        Vector3 pos = start;
        pos += dir * offset.z;
        pos += Vector3.up * offset.y;
        pos += GetNormalLine(dir, Vector3.up) * offset.x;
        return pos;
    }
    public static Vector3 MoveTransform(Vector3 start, Transform trans, Vector3 offset)
    {
        Vector3 pos = start;
        pos += trans.forward * offset.z;
        pos += trans.up * offset.y;
        pos += trans.right * offset.x;
        return pos;
    }

    public static List<Vector2> GetCirclePoints(Vector2 center, float radius, int segments )
    {
        List<Vector2> points = new List<Vector2>();
        float angleStep = 360f / segments; // 每份的角度  

        for (int i = 0; i < segments; i++)
        {
            float angle = -angleStep * i * Mathf.Deg2Rad; // 转换为弧度  
            float x = center.x + Mathf.Cos(angle) * radius;
            float y = center.y + Mathf.Sin(angle) * radius;
            points.Add(new Vector2(x, y));
        }

        return points;
    }
    static public bool IsFlagMask(int value, int flag)
    {
        return (value & flag) == flag;
    }


    public static bool IsPointInBox(Vector3 center, Vector3 dirIn, float fWidth, float fHeight, Vector3 targetPos, float targetRadius)
    {
        float fDir = GetAngle(dirIn);
        return IsPointInBox(center, fDir, fWidth, fHeight, targetPos, targetRadius);
    }
    public static bool IsPointInBox(Vector3 center, float fDir, float fWidth, float fHeight, Vector3 targetPos, float targetRadius)
    {
        var pos = RotateRound(targetPos, center, Vector3.up, fDir);
        if (pos.x > center.x - fWidth / 2 - targetRadius && pos.x < center.x + fWidth / 2 + targetRadius &&
            pos.z > center.z - fHeight / 2 - targetRadius && pos.z < center.z + fHeight / 2 + targetRadius)
            return true;
        return false;
    }
    public static bool IsPointInCircle(Vector3 center, float fRadius, Vector3 targetPos, float targetRadius, float fMin = 0)
    {
        center.y = 0;
        targetPos.y = 0;
        var dis = GetDistance(center, targetPos);
        if (dis > fRadius + targetRadius || dis < fMin)
            return false;
        return true;
    }
    public static bool IsPointInEllipse(Vector3 centerPos, Vector3 dirIn, float fMinRadius, float fMaxRadius, Vector3 pos, float targetRadius)
    {
        var posStart = centerPos - dirIn * fMinRadius;
        var posEnd = centerPos + dirIn * fMinRadius;

        var dis1 = GetDistance(pos, posStart);
        var dis2 = GetDistance(pos, posEnd);
        if (dis1 + dis2 < fMaxRadius * 2)
            return true;

        if (targetRadius > 0)
        {
            // 后去近的焦点
            var dirStart = posStart - pos;
            dirStart.Normalize();
            var dirEnd = posEnd - pos;
            dirEnd.Normalize();
            var angel = -CommonTools.GetAngle(dirStart, dirEnd);
            var dir = CommonTools.RotateVector(dirStart, Vector3.up, angel / 2);
            dir.Normalize();
            pos += dir * targetRadius;
        }
        dis1 = GetDistance(pos, posStart);
        dis2 = GetDistance(pos, posEnd);
        if (dis1 + dis2 < fMaxRadius * 2)
            return true;
        return false;
    }

    // 计算扇形和圆形是否相交
    public static bool IsCircleIntersectSector(Vector3 circleCenter, float circleRadius, Vector3 sectorCenter, Vector3 sectorDirection, float sectorRadius, float sectorAngle)
    {
        var distance = CommonTools.GetDistance(circleCenter, sectorCenter);
        if (distance > circleRadius + sectorRadius)
            return false;
        // 计算两个圆心的夹角是不是再扇形的加角内
        var line = circleCenter - sectorCenter;

        float foffsetAngle = CommonTools.GetAngle(line, sectorDirection);
        float fCheckAngel = Mathf.Rad2Deg * Mathf.Atan(circleRadius / distance);
        if (Mathf.Abs(foffsetAngle) - fCheckAngel < sectorAngle / 2)
            return true;

        return false;
    }


    public static bool IsPointInSector(Vector3 center, Vector3 dir, float radius, float angel, Vector3 pos, float targetRadius)
    {
        center.y = 0;
        pos.y = 0;
        var dir1 = pos - center;
        var dis = dir1.magnitude;
        var fCheckAngel = angel / 2;
        var fAngel = Vector3.Angle(dir, dir1);
        if (dis < targetRadius)
            return true;
        // 需要对判断半径做一次调整
        if (targetRadius > 0.1f && dis > 0.1f)
        {
            fCheckAngel += Mathf.Rad2Deg * Mathf.Atan(targetRadius / dis);
        }
        if (fAngel < fCheckAngel) // 判断角度
        {
            if (dis < radius + targetRadius)
            {
                return true;
            }
        }
        return false;
    }


    // 判断角色是否在相机照射范围内
    public static bool IsInCameraView(ObjectBase obj)
    {
        Camera camera = CameraMgr.Instance().GetCamera();
        if (camera == null)
            return false;
        Plane[] planes = GeometryUtility.CalculateFrustumPlanes(camera);
        SkinnedMeshRenderer smr = obj.transform.parent.GetComponentInChildren<SkinnedMeshRenderer>();
        if (smr == null)
            return false;
        if (GeometryUtility.TestPlanesAABB(planes, smr.bounds))
            return true;
        else
            return false;
    }
    public static bool IsInScene(Transform transform)
    {
        Vector2 worldPos = SG.UIMgr.Instance().WorldToScreenPoint(transform.position);
        float leftX = worldPos.x - transform.GetComponent<RectTransform>().sizeDelta.x / 2;
        float rightX = worldPos.x + transform.GetComponent<RectTransform>().sizeDelta.x / 2;

        float leftY = worldPos.y - transform.GetComponent<RectTransform>().sizeDelta.y / 2;
        float rightY = worldPos.y + transform.GetComponent<RectTransform>().sizeDelta.y / 2;
        if (leftX >= 0 && rightX <= Screen.width && leftY >= 0 && rightY <= Screen.height)
        {
            return true;
        }
        return false;
    }
    public static bool IsPivotInScene(Transform transform)
    {
        Vector2 worldPos = SG.UIMgr.Instance().WorldToScreenPoint(transform.position);
        if (worldPos.x >= 0 && worldPos.x <= Screen.width && worldPos.y >= 0 && worldPos.y <= Screen.height)
        {
            return true;
        }
        return false;
    }
    public static Vector3 ScreenToRectTransformPos(GameObject parent, Vector3 pos)
    {
        Vector3 p = SG.UIMgr.Instance().GetUILocalPosition(parent.GetComponent<RectTransform>(), pos);
        return p;
    }

    public static void ClearObjList(List<GameObject> objList)
    {
        foreach (var obj in objList)
            obj.StopOrDestroy();
        objList.Clear();
    }
    public static void SetSpriteRenderBlack(GameObject sp, float colorV, float a)
    {
        if (sp == null)
            return;
        SpriteRenderer ren = sp.GetComponent<SpriteRenderer>();
        float h;
        float s;
        float v;
        Color.RGBToHSV(ren.color, out h, out s, out v);
        Color c = Color.HSVToRGB(h, s, colorV);
        c.a = a;
        ren.color = c;
    }
    public static Vector3 GetRandomInsideUnitCircle(float distance)
    {
        return UnityEngine.Random.insideUnitCircle * distance;
    }

    public static float GetScreenScaleWidth()
    {
        return Screen.width / 1920;
    }
    public static float GetScreenScaleHeight()
    {
        return Screen.height / 1080;
    }


    // 方法：判断圆和矩形是否相交  
    public static bool IsCircleIntersectingRect(float2 circleCenter, float circleRadius, float2 pos, float2 size)
    {
        // 先计算圆心在不在大矩形内
        Rect rect = new Rect();
        rect.position = pos - circleRadius;
        rect.size = size + circleRadius * 2;
        if (!rect.Contains(circleCenter))
            return false;
        // 如果在大矩形内，就要判断十字区域
        // 将矩形的位置设为左下角  
        float xLeft = pos.x - circleRadius;
        float xRight = pos.x + circleRadius + size.x;

        float yTop = pos.y + circleRadius + size.y;
        float yBottom = pos.y - circleRadius;

        // 横轴得时候，只要中心离边低于半径，就肯定相交
        if (circleCenter.x >= xLeft && circleCenter.x <= xRight && circleCenter.y >= pos.y && circleCenter.y <= pos.y + size.y)
            return true;
        // 竖轴得时候，只要中心离边低于半径，就肯定相交
        if (circleCenter.y <= yTop && circleCenter.y >= yBottom && circleCenter.x >= pos.x && circleCenter.x <= pos.x + size.y)
            return true;

        //  四个角得时候,看看是不是在圆的半径里
        float2 lb = pos;
        float2 lt = pos;
        lt.y = pos.y + size.y;
        float2 rb = pos;
        rb.x = pos.x + size.x;
        float2 rt = pos + size;

        if (math.distance(circleCenter, lt) < circleRadius)
            return true;
        if (math.distance(circleCenter, lb) < circleRadius)
            return true;
        if (math.distance(circleCenter, rt) < circleRadius)
            return true;
        if (math.distance(circleCenter, rb) < circleRadius)
            return true;



        // 如果圆心在矩形的四个角形成的四个圆（半径为圆的半径）内部，则它们相交  
        // 这可以通过计算圆心到矩形四个角的距离，并检查这些距离是否都小于圆的半径来实现  
        // 但由于前面的检查已经排除了圆心在矩形边界外且距离大于半径的情况，  
        // 所以如果代码执行到这里，就意味着圆和矩形相交  

        // 因此，我们不需要再进行额外的计算，直接返回true  
        return false;
    }
}
